package tools

/*
 +----------------------------------------------------------------------
 + Title        : socketioServer
 + Author       : huwl
 + Version      : 1.0.0
 + Initial-Time : 2024-09-22
 + Last-time    : 这个文件最后修改的时间 + 修改人的名称
 + Desc         : socketio 服务
 +----------------------------------------------------------------------
*/

import (
	"fmt"
	"log"
	"net/http"
	"net/url"

	socketio "github.com/googollee/go-socket.io"
	"github.com/googollee/go-socket.io/engineio"
	"github.com/googollee/go-socket.io/engineio/transport"
	"github.com/googollee/go-socket.io/engineio/transport/polling"
	"github.com/googollee/go-socket.io/engineio/transport/websocket"
)

type SocketioServer struct {
	Server  *socketio.Server
	Clients map[string]socketio.Conn
}

// var mu sync.Mutex

/**
 * 创建 SOCKETIO SERVER
 *
 * @return *SocketioServer
 * @author huwl
 */
func NewSocketioServer() *SocketioServer {
	// 创建 SOCKETIO SERVER
	server := socketio.NewServer(&engineio.Options{
		Transports: []transport.Transport{
			&websocket.Transport{
				CheckOrigin: func(r *http.Request) bool {
					return true
				},
			},
			polling.Default,
			// &polling.Transport{
			// 	CheckOrigin: func(r *http.Request) bool {
			// 		return true
			// 	},
			// },
		},
	})

	// redis适配器,可选
	// adapter(适配器)的作用是共享socket信息。简单解释就是多个实例间共享socket
	// ok, err := server.Adapter(&socketio.RedisAdapterOptions{
	// 	Addr:    "127.0.0.1:6379",
	// 	Prefix:  "socket.io",
	// 	Network: "tcp",
	// })
	// if err != nil || !ok {
	// 	log.Fatal("socket-io adapter error:", err)
	// }

	socketioServer := &SocketioServer{
		Server:  server,
		Clients: make(map[string]socketio.Conn),
	}

	// 监听连接
	socketioServer.OnConnect()

	// 监听错误
	socketioServer.OnError()

	// 监听断开连接
	socketioServer.OnDisconnect()
	return socketioServer
}

/**
 * 监听连接
 *
 * @author huwl
 */
func (srv *SocketioServer) OnConnect() {
	// 监听连接
	srv.Server.OnConnect("/", func(socket socketio.Conn) error {
		log.Println(" ------------ 开始监听连接事件 --------------- ")
		socket.SetContext("")
		//通过query参数获取建立连接的uid
		params, _ := url.ParseQuery(socket.URL().RawQuery)
		uid := params.Get("uid")
		username := params.Get("username")
		token := params.Get("token")
		group := params.Get("group")

		fmt.Println("uid:", uid)
		fmt.Println("username:", username)
		fmt.Println("token:", token)
		fmt.Println("group:", group)
		user := map[string]interface{}{
			"uid":      uid,
			"username": username,
			"token":    token,
			"group":    group,
		}
		socket.SetContext(uid)
		socket.SetContext(user)

		// 加入一个房间
		// s.Join("test")
		socket.Join(uid)
		socket.Join(group)
		fmt.Println("connect id：", socket.ID())

		// 保存客户连接
		// mu.Lock()
		// srv.Clients[uid] = socket
		// mu.Unlock()
		return nil
	})
}

/**
 * 监听聊天消息事件
 *
 * @param string namespace -----------------------------------必传,命名空间
 * @param string sendEvent -----------------------------------必传,发送事件
 * @param string receiveEvent --------------------------------必传,接收事件
 * @author huwl
 */
func (srv *SocketioServer) OnChatMessage(namespace, sendEvent, receiveEvent string) {
	srv.Server.OnEvent(namespace, receiveEvent, func(socket socketio.Conn, data map[string]interface{}) {
		log.Println(" ------------ 开始监听聊天消息事件 --------------- ")
		log.Println("消息数据 = ", data)

		toUid, ok := data["to_uid"]
		if !ok || toUid == "" {
			socket.Emit("fail", Error("接收者错误"))
			return
		}

		log.Println("当前连接数：", srv.Server.Count())

		// 发送指定客户端
		srv.Server.BroadcastToRoom(namespace, toUid.(string), sendEvent, Success(data))

		// 判断发送完消息是否关闭当前连接
		isClose, ok := data["is_close"]
		if ok && isClose == "1" {
			log.Println("------------ 关闭当前连接 ---------------")
			err := socket.Close()
			if err != nil {
				log.Println("关闭当前连接错误信息：", err)
			}
		}
	})
}

/**
 * 监听房间消息事件
 *
 * @param string namespace -----------------------------------必传,命名空间
 * @param string sendEvent -----------------------------------必传,发送事件
 * @param string receiveEvent --------------------------------必传,接收事件
 * @author huwl
 */
func (srv *SocketioServer) OnRoomMessage(namespace string, sendEvent, receiveEvent string) {
	srv.Server.OnEvent(namespace, receiveEvent, func(socket socketio.Conn, data map[string]interface{}) {
		log.Println(" ------------ 开始监听房间消息事件 --------------- ")
		log.Println("消息数据 = ", data)
		room, ok := data["room"]
		if !ok || room == "" {
			socket.Emit("fail", Error("房间错误"))
			return
		}

		// 发送指定房间的所有客户端
		srv.Server.BroadcastToRoom(namespace, room.(string), sendEvent, data)
	})
}

/**
 * 监听命名空间消息事件
 *
 * @param string namespace -----------------------------------必传,命名空间
 * @param string sendEvent -----------------------------------必传,发送事件
 * @param string receiveEvent --------------------------------必传,接收事件
 * @author huwl
 */
func (srv *SocketioServer) OnNamespaceMessage(namespace string, sendEvent, receiveEvent string) {
	srv.Server.OnEvent(namespace, receiveEvent, func(socket socketio.Conn, data map[string]interface{}) {
		log.Println(" ------------ 开始监听命名空间消息事件 --------------- ")
		log.Println("消息数据 = ", data)
		namespace, ok := data["namespace"]
		if !ok || namespace == "" {
			socket.Emit("fail", Error("命名空间错误"))
			return
		}

		// 发送指定命名空间的所有客户端
		srv.Server.BroadcastToNamespace(namespace.(string), sendEvent, data)
	})
}

// // 监听指定
// server.OnEvent("/", "assign", func(s socketio.Conn, data map[string]interface{}) {
// 	fmt.Println("assign data:", data)
// 	toUid := data["to_uid"]

// 	server.BroadcastToRoom("/", toUid.(string), "replyAssign", map[string]interface{}{
// 		"from_uid": s.Context(),
// 		"content":  "kkkkkkkkkkkkkkk",
// 	})
// })

// // 监听消息
// server.OnEvent("/chat", "msg", func(s socketio.Conn, data map[string]interface{}) interface{} {
// 	s.SetContext(data)
// 	fmt.Println("/chat", data)
// 	return data
// })

// server.OnEvent("/", "bye", func(s socketio.Conn, data map[string]interface{}) string {
// 	last := s.Context().(string)
// 	fmt.Println("last =", last)
// 	fromUid, ok := data["from_uid"]
// 	if ok {
// 		mu.Lock()
// 		delete(clients, fromUid.(string))
// 		mu.Unlock()
// 	}
// 	s.Emit("bye", last)
// 	s.Close()
// 	return last
// })

/**
 * 监听错误,程序发生错误或者连接错误
 *
 * @author huwl
 */
func (srv *SocketioServer) OnError() {
	srv.Server.OnError("/", func(socket socketio.Conn, e error) {
		log.Println(" ------------ 开始监听错误事件 --------------- ")
		log.Println("错误信息：", e)
	})
}

/**
 * 监听断开连接
 *
 * @author huwl
 */
func (srv *SocketioServer) OnDisconnect() {
	srv.Server.OnDisconnect("/", func(socket socketio.Conn, reason string) {
		// Add the Remove session id. Fixed the connection & mem leak
		log.Println(" ------------ 开始监听断开连接事件 --------------- ")
		// user := s.Context().(map[string]interface{})
		// fmt.Println("user =", user)
		// 离开房间
		socket.LeaveAll()
		socket.SetContext("")
		log.Println("客户端【"+socket.RemoteAddr().String()+"】已断开,断开原因：", reason)
	})
}
